Quick Links
Beginner Section
Learn how to take your first steps using Traversecraft with this tutorial.
We will try to create a simulation that resembles this.
Import required modules¶
Let's start by importing the required module form the main library.
It's always a good idea to check whether the library is installed or not. The below command will install the library if the library is not already installed.
!pip install -i https://test.pypi.org/simple/ TraverseCraft
Looking in indexes: https://test.pypi.org/simple/ Requirement already satisfied: TraverseCraft in /media/srajan/Data/Project/LibraryTests/envs/lib/python3.8/site-packages (0.9.0) Requirement already satisfied: prettytable in /media/srajan/Data/Project/LibraryTests/envs/lib/python3.8/site-packages (from TraverseCraft) (0.7.3.dev122)
Let's import Graph World and Graph Agent¶
we will import the CreateGraphWorld
class from the world
module and GraphAgent
class from the agent
module.
Note: It is very important to call the right agent for the given world, otherwise the module will through an error. Each world behave differently and each agent is tailored for that world only.
Remark: Don't worry if during the importing the library prints the OS Type. Actually the library uses some internal variables which are OS depended. It is necessary that the OS type printed and your OS type matches. If it does't match please report this.
from traverseCraft.world import CreateGraphWorld
from traverseCraft.agent import GraphAgent
OS Type: Linux
Hello Graph World¶
Let's start with a simple Hello Graph World program to get familiarize with the library.
We will create a simple Graph as shown below with the default settings on.
World Information¶
Before creating the Graph World we have to first create the world blueprint/template. We call this blueprint/template as world information. This is like a abstract view of your world.
The world information will be a dictionary with keys and values as the following:
adj
: a dictionary of adjacency list containing each node ID as key and value as a list of ID's of neighbors.position
: a dictionary containing each node ID as key and value as a tuple containing position of the node on the world.goals
: a list containing node IDs.
These are the mandatory keys, which have to be present in the world information.
Note:
- You only have to pass node IDs which can be a
char
,str
,int
and the library will use it's internal data nodes to create the Graph along with world creation. You can access each node and Graph information from the library itself. This will also be helpful if you further want to modify/customize the nodes. The keys mention above in the world information are only the necessary key's but there are other keys as well.- The position of each node will be the coordinates. The (0,0) coordinate is you screens top left corner. Please consider drawing the world on a paper before actually writing the world abstract information.
- Please refer the API Reference section for more information.
# graph world information
graphWorldInfo = {
'adj': {
'A': ['B', 'C'],
'B': ['C', 'D', 'E'],
'C': ['B', 'F'],
'D': ['E'],
'E': ['F', 'G'],
'F': ['E', 'G'],
'G': []
},
'position': {
'A': (100, 200),
'B': (200, 100),
'C': (200, 300),
'D': (300, 200),
'E': (400, 100),
'F': (400, 300),
'G': (500, 200)
},
'goals': ['G']
}
Remark: you can see that we are only using the abstract information and passing this information to the library. The rest will be taken care by the library like the actual tree data structure creation, world creation etc. this will help the user to save a lot of time and in return help the user to be more creative and allow the user to make complex world easily with only the abstract information.
Create our Hello Graph World¶
Now, we have our world abstract information, we will pass this information to create the Graph world object.
# First let's Create a Graph world object!
graphWorld = CreateGraphWorld(worldName="Hello World", worldInfo=graphWorldInfo)
Compile our Hello Graph World¶
since, we are just creating a simple Graph world with all the default settings, we are ready to compile our world.
Note: Once you compile the world you can't change the structure of the world. So make sure that you do all the changes before compiling the world.
graphWorld.constructWorld()
Let's see some basic information about our Hello World!¶
you can use a simple print()
statement or you can use the builtin function aboutWorld()
to get the world information as a string.
print(graphWorld)
+-------------------------+-------------+ | Attribute | Value | +-------------------------+-------------+ | World Name | Hello World | | Goal Nodes | ['G'] | | Width | 3286 | | Height | 1080 | | Node Radius | 20 | | Font Size | 12 | | Font Bold | True | | Font Italic | True | | Node Color | gray | | Goal Color | green | | Line Thickness | 2 | | Arrow Shape | (10, 12, 5) | | Button Background Color | #7FC7D9 | | Button Foreground Color | #332941 | | Text Font | Helvetica | | Text Size | 24 | | Text Weight | bold | | Button Text | Start Agent | +-------------------------+-------------+
print(graphWorld.aboutWorld())
+-------------------------+-------------+ | Attribute | Value | +-------------------------+-------------+ | World Name | Hello World | | Goal Nodes | ['G'] | | Width | 3286 | | Height | 1080 | | Node Radius | 20 | | Font Size | 12 | | Font Bold | True | | Font Italic | True | | Node Color | gray | | Goal Color | green | | Line Thickness | 2 | | Arrow Shape | (10, 12, 5) | | Button Background Color | #7FC7D9 | | Button Foreground Color | #332941 | | Text Font | Helvetica | | Text Size | 24 | | Text Weight | bold | | Button Text | Start Agent | +-------------------------+-------------+
help(graphWorld)
Help on CreateGraphWorld in module traverseCraft.world object: class CreateGraphWorld(builtins.object) | CreateGraphWorld(worldName: str, worldInfo: dict, radius: int = 20, fontSize: int = 12, fontBold: bool = True, fontItalic: bool = True, nodeColor: str = 'gray', goalColor: str = 'green', width: int = 3286, height: int = 1080, lineThickness: int = 2, arrowShape: tuple = (10, 12, 5), buttonBgColor: str = '#7FC7D9', buttonFgColor: str = '#332941', textFont: str = 'Helvetica', textSize: int = 24, textWeight: str = 'bold', buttonText: str = 'Start Agent', logoPath: str = None) | | Class representing a graph world. | | | Parameters: | - worldName (str): The name of the world. | - _worldInfo (dict): A dictionary containing information about the world. | - 'goals' (list): List of goal node IDs. | - 'adj' (dict): Adjacency list representing graph connections. | - 'position' (dict): Dictionary of node positions with node IDs as keys. | - 'edges' (dict, optional): Dictionary of edge value. Default each edge is assigned a value of 1. | - 'vals' (dict, optional): Dictionary of node values. Default each node is assigned the value same as its ID. | - radius (int): The radius of the nodes in the world visualization. Default is 20. | - fontSize (int): The font size of the node labels. Default is 12. | - fontBold (bool): Whether to use bold font for the node labels. Default is True. | - fontItalic (bool): Whether to use italic font for the node labels. Default is True. | - nodeColor (str): The color of the nodes. Default is "gray". | - goalColor (str): The color of the goal nodes. Default is "green". | - width (int): The width of the world visualization canvas. Default is SCREEN_WIDTH. | - height (int): The height of the world visualization canvas. Default is SCREEN_HEIGHT. | - lineThickness (int): The thickness of the lines connecting the nodes. Default is 2. | - arrowShape (tuple): The shape of the arrows indicating the direction of the edges. Default is (10, 12, 5). | - buttonBgColor (str): The background color of the buttons. Default is "#7FC7D9". | - buttonFgColor (str): The foreground color of the buttons. Default is "#332941". | - textFont (str): The font family of the button text. Default is "Helvetica". | - textSize (int): The font size of the button text. Default is 24. | - textWeight (str): The font weight of the button text. Default is "bold". | - buttonText (str): The text displayed on the buttons. Default is "Start Agent". | - logoPath (str, optional): The file path to the logo image. Default is traverseCraft logo. | | Attributes: | - worldID (str): Class identifier for the graph world. | - _worldName (str): The name of the world. | - _worldInfo (dict): Dictionary containing the world's information. | - _graphRootId (str): The ID of the root node. | - _goalIds (list): List of goal node IDs. | - _position (dict): Dictionary of node positions. | - _width (int): The width of the visualization canvas. | - _height (int): The height of the visualization canvas. | - _radius (int): The radius of the nodes. | - _nodeColor (str): The color of the nodes. | - _goalColor (str): The color of the goal nodes. | - _fontSize (int): The font size of the node labels. | - _fontBold (bool): Whether the node labels are bold. | - _fontItalic (bool): Whether the node labels are italic. | - _lineThickness (int): The thickness of the lines connecting the nodes. | - _arrowShape (tuple): The shape of the arrows indicating the direction of the edges. | - _logoPath (str): The file path to the logo image. | - _root (Tk): The root Tkinter object. | - _canvas (Canvas): The canvas object for drawing the world. | - nodeMap (dict): Dictionary mapping node IDs to canvas objects. | - _visited (dict): Dictionary tracking visited nodes. | - _agent: The agent in the world. | - _nodeObj (dict): Dictionary mapping node IDs to node objects. | - _nodeTextObj (dict): Dictionary mapping node IDs to node label objects. | - _buttonBgColor (str): The background color of the buttons. | - _buttonFgColor (str): The foreground color of the buttons. | - _buttonText (str): The text displayed on the buttons. | - _textFont (str): The font family of the button text. | - _textSize (int): The font size of the button text. | - _textWeight (str): The font weight of the button text. | | Methods defined here: | | __init__(self, worldName: str, worldInfo: dict, radius: int = 20, fontSize: int = 12, fontBold: bool = True, fontItalic: bool = True, nodeColor: str = 'gray', goalColor: str = 'green', width: int = 3286, height: int = 1080, lineThickness: int = 2, arrowShape: tuple = (10, 12, 5), buttonBgColor: str = '#7FC7D9', buttonFgColor: str = '#332941', textFont: str = 'Helvetica', textSize: int = 24, textWeight: str = 'bold', buttonText: str = 'Start Agent', logoPath: str = None) | Initializes the Graph World. | | __str__(self) | Describes the attributes of the world. | | Parameters: | None | | Returns: | str: The attributes of the world. | | aboutWorld(self) | Describes the attributes of the world. | | Parameters: | None | Returns: | str: The attributes of the world. | | changeNodeColor(self, nodeId, color) | Changes the color of a node in the graph. | | Args: | nodeId (int): The ID of the node to change the color of. | color (str): The new color to set for the node. | | Returns: | None | | changeNodeText(self, nodeId, newText) | Changes the text of a node in the graph. | | Parameters: | nodeId (int): The ID of the node to change the text of. | newText (str): The new text to set for the node. | | Returns: | | constructWorld(self) | Constructs the graph world. | | Parameters: | self (World): The World instance. | | Returns: | None | | getNode(self, nodeId) | Returns the pointer to the node with the given nodeId. | | Parameters: | nodeId: The ID of the node to retrieve the pointer for. | | Returns: | Node: The pointer to the node with the given nodeId. | | setAgent(self, agent) | Set the agent for the world. | | Parameters: | agent (Agent): The agent to be set. | | Returns: | None | | showWorld(self) | Displays the world. | | Parameters: | None | Returns: | None | | summary(self) | Generates a summary of the world. | | Parameters: | None | Returns: | str: The summary of the world. | | ---------------------------------------------------------------------- | Data descriptors defined here: | | __dict__ | dictionary for instance variables (if defined) | | __weakref__ | list of weak references to the object (if defined) | | ---------------------------------------------------------------------- | Data and other attributes defined here: | | worldID = 'GRAPHWORLD'
Let's create our agent which will interact with the world.¶
here also we will create a simple graph agent with the default settings.
graphAgent = GraphAgent(agentName="Graph Agent", world=graphWorld)
Let's Set the Start State¶
Unlike from the tree world, here the agent can select any node as it's start state. By default the library chooses the first node in the nodeMap
as the start state, but it will be a problem every time we run the simulation as we are not sure which will be the start state. Thus it's always recommended to set the start state. We will use the setStartState()
method of the agent class to set the start state of the agent.
graphAgent.setStartState('A')
Let's see some basic information about our graph Agent
.¶
you can use a simple print()
statement or you can use the builtin function aboutAgent()
to get the agent information as a string.
print(graphAgent)
+---------------+-------------+ | Attribute | Value | +---------------+-------------+ | Agent Name | Graph Agent | | Agent Color | blue | | World Name | Hello World | | World ID | GRAPHWORLD | | Start Node ID | A | +---------------+-------------+
print(graphAgent.aboutAgent())
+---------------+-------------+ | Attribute | Value | +---------------+-------------+ | Agent Name | Graph Agent | | Agent Color | blue | | World Name | Hello World | | World ID | GRAPHWORLD | | Start Node ID | A | +---------------+-------------+
Connect Our Agent with the World¶
Now, we have our world ready and constructed and we also have our agent ready, but the world doesn't know the agent and the agent does't know the world. We have to connect the agent with the world. We will use the .setAgent()
method of the world to connect the agent with the world.
graphWorld.setAgent(graphAgent)
Algorithm¶
Now, we have connected the agent with the world, but we did not told the agent what to do in the world.
The agent have a method setAlgorithmCallBack()
which takes a function as a argument.
This function will be run during the simulation.
Note: Make sure that the function you are passing in the
setAlgorithmCallBack()
method does not take any argument.
Let's first create our function which will tell the agent what to do.¶
We will use the moveAgent()
method of the agent class to move the agent.
We will start from node 'A', which is the root node as well as the start position of the agent by default and we will move the agent in the following manner:
'A' -> 'B' -> 'C' -> 'B' -> 'D' -> 'E' -> 'F' -> 'E' -> 'G'
def whatToDo():
print("I am a Graph Agent and I am going to move around the world!")
graphAgent.moveAgent('B')
graphAgent.moveAgent('C')
graphAgent.moveAgent('B')
graphAgent.moveAgent('D')
graphAgent.moveAgent('E')
graphAgent.moveAgent('F')
graphAgent.moveAgent('E')
graphAgent.moveAgent('G')
print("I am done moving around the world!")
We are ready with our algorithm¶
Lets set the algorithm to tell the agent what to do.
graphAgent.setAlgorithmCallBack(whatToDo)
Display the world and Start the Simulation!¶
Now, we are all set. We will first show the world using the showWorld()
method and then on the world there is a button at the bottom to start the simulation.
Warning: Always make sure that the method
showWorld()
is called when you are ready to simulate, because after this no change can be made on the world or the agent.
graphWorld.showWorld()
I am a Graph Agent and I am going to move around the world! I am done moving around the world!
In the window You can see the heatmap forming where the agent is going. This is the default function of the agent, but you can switch off this feature also by simple changing the value of heatMapView
to False
during the tree agent object creation.
You can also see there is a slight delay in the movement of the agent, this is also a feature of agent, you can control the delay while calling the moveAgent
method by the parameter delay
.
Let's see the summary¶
The agent and the world keep some records, that we can generate and see.
The Agent have information about the time taken to run the whole simulation.¶
We can see this information using the summary
method.
print(graphAgent.summary())
+--------------+---------------------------+ | Attribute | Value | +--------------+---------------------------+ | Start Time | Thu, 20 Jun 2024 06:17:30 | | End Time | Thu, 20 Jun 2024 06:17:38 | | Elapsed Time | 8.029 sec | +--------------+---------------------------+
The World have information about the visited count after the whole simulation.¶
We can see this information using the summary
method.
print(graphWorld.summary())
+---------+------------------+ | Node ID | Number of Visits | +---------+------------------+ | G | 1 | | E | 2 | | F | 1 | | C | 1 | | D | 1 | | B | 2 | | A | 1 | +---------+------------------+
help(graphAgent)
Help on GraphAgent in module traverseCraft.agent object: class GraphAgent(builtins.object) | GraphAgent(world, agentName: str, agentColor: str = 'blue', startNodeId=None, heatMapView: bool = True, heatMapColor: str = '#FFA732', heatGradient: float = 0.05) | | The Graph Agent class. | | Parameters: | world (CreateGridWorld): The world object that the agent belongs to. | agentName (str): The name of the agent. | agentColor (str, optional): The color of the agent. Defaults to "blue". | heatMapView (bool, optional): Flag indicating whether to enable heat map view. Defaults to True. | heatMapColor (str, optional): The color of the heat map. Defaults to "#FFA732". | heatGradient (float, optional): The gradient of the heat map. Defaults to 0.05. | | Attributes: | _worldObj (CreateGraphWorld): The graph world object. | _worldID (str): The ID of the world. | _root (Tk): The root Tkinter object from the graph world. | _agentName (str): The name of the agent. | _agentColor (str): The color of the agent. | _heatMapView (bool): Indicates if the heat map view is enabled. | _heatMapColor (str): The color of the heat map. | _heatMapBaseColor (str): The base color of the heat map. | _heatGradient (float): The gradient value for the heat map. | _currentNode (GraphNode): The current node the agent is on. | _graphRoot (GraphNode): The root node of the graph. | algorithmCallBack (function): Callback function for the agent's algorithm. | _startTime (float): The start time of the agent. | _endTime (float): The end time of the agent. | | Methods defined here: | | __init__(self, world, agentName: str, agentColor: str = 'blue', startNodeId=None, heatMapView: bool = True, heatMapColor: str = '#FFA732', heatGradient: float = 0.05) | Initialize self. See help(type(self)) for accurate signature. | | __str__(self) | Describes the attributes of the world. | | Parameters: | None | | Returns: | function(): The attributes of the world. | | aboutAgent(self) | Prints information about the agent. | | Parameters: | None | | Returns: | str: A string containing information about the agent. | | checkGoalState(self, nodeId) | Check if the given node is a goal state. | | Parameters: | node: The ID of the node to be checked. | | Returns: | bool: True if the node is a goal state, False otherwise. | | getHeatMapColor(self, value: float) | Returns the color for a given value on a heat map. | | Parameters: | value (float): The value to map to a color on the heat map. | | Returns: | tuple: The RGB color value for the given value on the heat map. | | moveAgent(self, nodeId, delay: int = 1) | Moves the agent to the specified node. | | Args: | nodeId: The ID of the node to which the agent should be moved. | delay (optional): The delay (in seconds) before moving to the next node. Default is 1 second. | | Returns: | bool: True if the agent was successfully moved to the node, False otherwise. | | runAlgorithm(self) | Executes the algorithm callback function. | | Raises: | ValueError: If the algorithm callback function is not set. | | setAlgorithmCallBack(self, algorithmCallBack) | Set the callback function for the algorithm. | | Parameters: | algorithmCallBack (function): The callback function to be set. | | Returns: | None | | setStartState(self, nodeId) | Sets the start state of the agent to the specified node. | | Args: | nodeId: The ID of the node to set as the start state. | | Raises: | ValueError: If the specified node ID is invalid. | | summary(self) | Returns a summary of the agent run. | | Parameters: | None | Returns: | str: A summary of the agent run. | | ---------------------------------------------------------------------- | Data descriptors defined here: | | __dict__ | dictionary for instance variables (if defined) | | __weakref__ | list of weak references to the object (if defined)
This covers the basic of how to create a simple Graph World and Graph Agent. How to connect the created agent with the world and how to run a simple algorithm to simulate the agent on the world.
Next, in the Advance Section
we will learn about how to use some advance features and settings to customize the world according to your need.
Thanks!